//
//  XSAVPlayer.m
//  AudioVideo
//
//  Created by xueshan1 on 2019/8/23.
//  Copyright © 2019 xueshan1. All rights reserved.
//

#import "XSAVPlayer.h"
#import <AVFoundation/AVFoundation.h>

#import <MediaPlayer/MediaPlayer.h>
//asset key
NSString *const SF_Playable_Key = @"playable";
//playerItem key
NSString *const SF_Status_Key = @"status";
NSString *const SF_LoadedTimeRanges_Key = @"loadedTimeRanges";
NSString *const SF_PlaybackBufferEmpty_Key = @"playbackBufferEmpty";
NSString *const SF_PlaybackLikelyToKeepUp_Key = @"playbackLikelyToKeepUp";


@interface XSAVPlayer ()
{
    BOOL _isInit;
}

@property(nonatomic,strong)NSURL *audioURL;
@property(nonatomic,strong)NSURL *videoURL;
@property(nonatomic,strong)AVPlayer *player;
@property(nonatomic,strong)AVPlayerItem *playerItem;
//进度观察者
@property(nonatomic,strong)id progressObserver;
//是否有其他声音播放
@property(nonatomic,assign)BOOL isOtherPlaying;
//在后台
@property(nonatomic,assign)BOOL isBackground;

@property(nonatomic,weak)UIView *playView;

@property(nonatomic,strong)UISlider *volumnSlider;

@end

@implementation XSAVPlayer

+ (instancetype)shareInstance{
    static XSAVPlayer *player = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        player = [[XSAVPlayer alloc]init];
    });
    return player;
}

+ (instancetype)audioInstance{
    static XSAVPlayer *audioPlayer = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        audioPlayer = [[XSAVPlayer alloc]init];
    });
    return audioPlayer;
}

- (void)dealloc{
    [[NSNotificationCenter defaultCenter]removeObserver:self];
    [self sf_deallocPlayer];
}

//初始化
- (void)initPlayer{
    _isInit = YES;
    //默认值
    self.isBackground = NO;
    self.playState = XSAVPlayerState_Stopped;
    [[AVAudioSession sharedInstance]setActive:YES error:nil];
    self.isOtherPlaying = [AVAudioSession sharedInstance].isOtherAudioPlaying;
    self.sessionCategory = XSAVPlayerSessionCategory_Playback;
    self.needCustomeCache = NO;
    self.isRecyclePlay = YES;
    self.playStopTimePercent = 1.0;
    
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(sf_appWillResignActive) name:UIApplicationWillResignActiveNotification object:nil];
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(sf_appDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(sf_audioPlayerInterrupted:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];
    
}
#pragma mark - 播放音频
- (void)sf_playAudioWithURLString:(NSString *)audioURLString isLocalFile:(BOOL)isLocal{
    if (!audioURLString.length) {
        return;
    }
    [self sf_playAudioWithURL:[NSURL URLWithString:audioURLString] isLocalFile:isLocal];
}

- (void)sf_playAudioWithURL:(NSURL *)audioURL isLocalFile:(BOOL)isLocal{
    if (![audioURL isKindOfClass:[NSURL class]]) {
        return;
    }
    if (!_isInit) {
        [self initPlayer];
    }
    self.audioURL = audioURL;
    [self sf_removeItemObserver];
    
    if (isLocal) {
        self.playerItem = [AVPlayerItem playerItemWithURL:[NSURL fileURLWithPath:audioURL.absoluteString]];
    }else{
        self.playerItem = [self loadItemWithURL:audioURL];
    }
    
    _player = [[AVPlayer alloc]init];
    
    [self.player replaceCurrentItemWithPlayerItem:self.playerItem];
    
    [self sf_addItemObserver];
    
}
#pragma mark - 播放视频
- (void)playVideoWithURLString:(NSString *)urlString onPlayView:(UIView *)playView isLocalFile:(BOOL)isLocal{
    [self playVideoWithURLString:urlString onPlayView:playView belowView:nil isLocalFile:isLocal];
}
- (void)playVideoWithURLString:(NSString *)urlString onPlayView:(UIView *)playView belowView:(UIView *)belowView  isLocalFile:(BOOL)isLocal{
    if (![urlString isKindOfClass:[NSString class]] || urlString.length == 0) {
        return;
    }
    if (!_isInit) {
        [self initPlayer];
    }
    [self sf_removeItemObserver];
    
    if (isLocal) {
        if (![[NSFileManager defaultManager]fileExistsAtPath:urlString]){
            NSLog(@"资源不存在:%@",urlString);
            //            return;
        }
        self.videoURL = [NSURL fileURLWithPath:urlString];
        self.playerItem = [AVPlayerItem playerItemWithURL:self.videoURL];
    }else{
        self.videoURL = [NSURL URLWithString:urlString];
        self.playerItem = [self loadItemWithURL:self.videoURL];
    }
    
    self.playView = playView;
    _player = [[AVPlayer alloc]init];
       
    AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
    playerLayer.frame = playView.bounds;
    playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
    if (belowView) {
        [playView.layer insertSublayer:playerLayer below:belowView.layer];
    }else{
        [playView.layer addSublayer:playerLayer];
    }
    [self.player replaceCurrentItemWithPlayerItem:self.playerItem];
    
    [self sf_addItemObserver];
    
    
}

- (void)playVideoWithPlayItem:(AVPlayerItem *)playItem onPlayView:(UIView *)playView belowView:(UIView *)belowView {
    if (playItem == nil) {
        return;
    }
    if (!_isInit) {
        [self initPlayer];
    }
    [self sf_removeItemObserver];
    
    self.playerItem = playItem;
    self.playView = playView;
    _player = [[AVPlayer alloc]init];
       
    AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
    playerLayer.frame = playView.bounds;
    playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
    if (belowView) {
        [playView.layer insertSublayer:playerLayer below:belowView.layer];
    }else{
        [playView.layer addSublayer:playerLayer];
    }
    [self.player replaceCurrentItemWithPlayerItem:self.playerItem];
    
    [self sf_addItemObserver];
}
- (void)playVideoWithAVAsset:(AVAsset *)avasset onPlayView:(UIView *)playView belowView:(UIView *)belowView{
    if (!avasset) {
        return;
    }
    if (!_isInit) {
        [self initPlayer];
    }
    [self sf_removeItemObserver];
    
    self.playerItem = [AVPlayerItem playerItemWithAsset:avasset];;
    self.playView = playView;
    _player = [[AVPlayer alloc]init];
       
    AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
    playerLayer.frame = playView.bounds;
    playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
    if (belowView) {
        [playView.layer insertSublayer:playerLayer below:belowView.layer];
    }else{
        [playView.layer addSublayer:playerLayer];
    }
    [self.player replaceCurrentItemWithPlayerItem:self.playerItem];
    
    [self sf_addItemObserver];
    
}

- (AVPlayerItem *)loadItemWithURL:(NSURL *)audioURL{
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:audioURL options:nil];
//    if (self.needCustomeCache) [asset.resourceLoader setDelegate:self.resourceLoader queue:dispatch_get_main_queue()];
    [asset loadValuesAsynchronouslyForKeys:@[SF_Playable_Key] completionHandler:^{
        dispatch_async(dispatch_get_main_queue(), ^{
            if (!asset.isPlayable) {
                NSLog(@"不能播放");
                if (self.delegate && [self.delegate respondsToSelector:@selector(sf_playerPlayFailed:)]) {
                    [self.delegate sf_playerPlayFailed:@"url不能播放"];
                }
                self.playState = XSAVPlayerState_Failed;
                [asset cancelLoading];
            }
            
        });
    }];
    
    return [AVPlayerItem playerItemWithAsset:asset];
}


//播放
- (void)sf_audioPlay{
    if (self.playState == XSAVPlayerState_Failed) {
        [self playVideoWithURLString:self.audioURL.absoluteString onPlayView:self.playView isLocalFile:YES];
        NSLog(@"播放失败");
    }else{
        self.playState = XSAVPlayerState_ReadyPlay;
        [self.player play];
    }
    
}
//暂停
- (void)sf_audioPause{
    
    self.playState = XSAVPlayerState_Pause;
    [self.player pause];
}
//释放播放器
- (void)sf_deallocPlayer{
    [self sf_audioPause];
    //解除激活,并还原其他应用播放器声音
    if (self.isOtherPlaying) {
        [[AVAudioSession sharedInstance]setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
    }else{
        [[AVAudioSession sharedInstance]setActive:NO error:nil];
    }
    
    [self sf_removeItemObserver];
    
    if (self.player) {
        self.player = nil;
    }
    
    [self.player.currentItem cancelPendingSeeks];
    [self.player.currentItem.asset cancelLoading];
    _isInit = NO;
}

//重新播放
- (void)recyclePlay{
    if (!self.player) {
        return;
    }
    
    CMTime startTime = CMTimeMakeWithSeconds(self.sf_totalTime * self.playStartTimePercent, self.player.currentTime.timescale);
    [self.player seekToTime:startTime];
    [self sf_audioPlay];
    
}
#pragma mark - notification
//播放结束
- (void)sf_playerDidPlayToEndTime:(NSNotification *)notification{
//    NSLog(@"播放结束");
    self.playState = XSAVPlayerState_Stopped;
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(sf_playerDidPlayToEndTime:)]) {
        [self.delegate sf_playerDidPlayToEndTime:self];
    }
    
    if (self.isRecyclePlay) {
        [self recyclePlay];
    }
    
}
//被打断(其他音频/来电话)
- (void)sf_audioPlayerInterrupted:(NSNotification *)notification{
    NSDictionary *dic = notification.userInfo;
    if ([dic[AVAudioSessionInterruptionTypeKey] integerValue] == 1) {
        //被打断
        [self sf_audioPause];
        self.playState = XSAVPlayerState_Stopped;
        
    }else{
        //打断结束
        if ([dic[AVAudioSessionInterruptionOptionKey] unsignedIntegerValue] == 1) {
            [self sf_audioPlay];
            self.playState = XSAVPlayerState_Playing;
        }
    }
    
}
- (void)sf_appWillResignActive{
    self.isBackground = YES;
    //    [self sf_audioPause];
}
- (void)sf_appDidBecomeActive{
    //    if (self.player && self.isBackground) {
    //        [self sf_audioPlay];
    //    }
    
    self.isBackground = NO;
}

- (void)sf_removeItemObserver{
    if (self.player.currentItem) {
        [self.player.currentItem removeObserver:self forKeyPath:SF_Status_Key];
        [self.player.currentItem removeObserver:self forKeyPath:SF_LoadedTimeRanges_Key];
        [self.player.currentItem removeObserver:self forKeyPath:SF_PlaybackBufferEmpty_Key];
        [self.player.currentItem removeObserver:self forKeyPath:SF_PlaybackLikelyToKeepUp_Key];
    }
    
    if (self.player) {
        [[NSNotificationCenter defaultCenter]removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
        [self.player removeTimeObserver:self.progressObserver];
        _progressObserver = nil;
    }
    
}
- (void)sf_addItemObserver{
    
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(sf_playerDidPlayToEndTime:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
    [self.player.currentItem addObserver:self forKeyPath:SF_Status_Key options:NSKeyValueObservingOptionNew context:nil];
    [self.player.currentItem addObserver:self forKeyPath:SF_LoadedTimeRanges_Key options:NSKeyValueObservingOptionNew context:nil];
    [self.player.currentItem addObserver:self forKeyPath:SF_PlaybackBufferEmpty_Key options:NSKeyValueObservingOptionNew context:nil];
    [self.player.currentItem addObserver:self forKeyPath:SF_PlaybackLikelyToKeepUp_Key options:NSKeyValueObservingOptionNew context:nil];
    
    
    kWeakSelf;
    self.progressObserver = [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
        
        weakSelf.sf_currentTime = (CGFloat)CMTimeGetSeconds(time);
        if (weakSelf.sf_totalTime) {
            weakSelf.sf_progress = weakSelf.sf_currentTime/weakSelf.sf_totalTime;
        }
        
        if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(sf_player:progress:currentTime:totalTime:)]) {
            [weakSelf.delegate sf_player:weakSelf progress:weakSelf.sf_progress currentTime:weakSelf.sf_currentTime totalTime:weakSelf.sf_totalTime];
        }
        if (weakSelf.progressChangeBlock) {
            weakSelf.progressChangeBlock(weakSelf.sf_progress);
        }
        
        if (weakSelf.playState == XSAVPlayerState_ReadyPlay) {
            weakSelf.playState = XSAVPlayerState_Playing;
        }
//        NSLog(@"当前时间:%f,进度:%f",weakSelf.sf_currentTime,weakSelf.sf_progress);
        
        if (weakSelf.playStopTimePercent < 1.0) {
            if (weakSelf.sf_progress >= weakSelf.playStopTimePercent) {
                 [weakSelf setProgressValus:weakSelf.playStartTimePercent];
            }
        }
        
    }];
    
}
#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    if (object == self.player.currentItem) {
        if ([keyPath isEqualToString:SF_Status_Key]) {
            switch (_playerItem.status) {
                case AVPlayerItemStatusUnknown:
                    self.playState = XSAVPlayerState_Failed;
                    NSLog(@"AVPlayerItemStatusUnknown:未知错误");
                    if (self.delegate && [self.delegate respondsToSelector:@selector(sf_playerPlayFailed:)]) {
                        [self.delegate sf_playerPlayFailed:@"未知错误"];
                    }
                    break;
                case AVPlayerItemStatusReadyToPlay:
                    //准备播放
                    self.playState = XSAVPlayerState_ReadyPlay;
                    [self sf_audioPlay];
                    
                    break;
                case AVPlayerItemStatusFailed:
                    self.playState = XSAVPlayerState_Failed;
                    NSLog(@"AVPlayerItemStatusFailed:准备失败");
                    if (self.delegate && [self.delegate respondsToSelector:@selector(sf_playerPlayFailed:)]) {
                        [self.delegate sf_playerPlayFailed:@"准备失败"];
                    }
                    break;
                    
                default:
                    break;
            }
            
        }else if ([keyPath isEqualToString:SF_LoadedTimeRanges_Key]){//缓存时间
            self.sf_totalTime = CMTimeGetSeconds(self.player.currentItem.duration);
            //            NSLog(@"总时长:%f",self.sf_totalTime);
            [self addBufferProgressObserver];
        }else if ([keyPath isEqualToString:SF_PlaybackBufferEmpty_Key]){//缓冲是空的
            if (self.playerItem.playbackBufferEmpty) {
                self.playState = XSAVPlayerState_Buffering;
            }
            
        }else if ([keyPath isEqualToString:SF_PlaybackLikelyToKeepUp_Key]){//缓冲达到可播放
            NSLog(@"缓冲达到可播放");
        }
        
    }
}
- (void)addBufferProgressObserver{
    CMTimeRange timeRange = [self.playerItem.loadedTimeRanges.firstObject CMTimeRangeValue];
    CGFloat startSeconds = CMTimeGetSeconds(timeRange.start);
    CGFloat durationSeconds = CMTimeGetSeconds(timeRange.duration);
    if (self.sf_totalTime != 0) {
        self.sf_bufferProgress = (startSeconds + durationSeconds)/self.sf_totalTime;
    }
//    NSLog(@"缓冲进度:%f",self.sf_bufferProgress);
    if (self.delegate && [self.delegate respondsToSelector:@selector(sf_player:bufferProgress:totalTime:)]) {
        [self.delegate sf_player:self bufferProgress:self.sf_bufferProgress totalTime:self.sf_totalTime];
    }
    
}

#pragma mark - set / get
- (void)setPlayerItem:(AVPlayerItem *)playerItem{
    _playerItem = playerItem;
    
}
- (void)setSessionCategory:(XSAVPlayerSessionCategory)sessionCategory{
    _sessionCategory = sessionCategory;
    switch (sessionCategory) {
        case XSAVPlayerSessionCategory_Ambient:
            [[AVAudioSession sharedInstance]setCategory:AVAudioSessionCategoryAmbient error:nil];
            break;
        case XSAVPlayerSessionCategory_SoloAmbient:
            [[AVAudioSession sharedInstance]setCategory:AVAudioSessionCategorySoloAmbient error:nil];
            break;
        case XSAVPlayerSessionCategory_Playback:
            [[AVAudioSession sharedInstance]setCategory:AVAudioSessionCategoryPlayback error:nil];
            break;
            
        default:
            break;
    }
}
- (void)setPlayState:(XSAVPlayerState)playState{
    _playState = playState;
    if (self.delegate && [self.delegate respondsToSelector:@selector(sf_playerPlayState:)]) {
        [self.delegate sf_playerPlayState:playState];
    }
}
- (void)setSf_rate:(CGFloat)sf_rate{
    _sf_rate = sf_rate;
    self.player.rate = sf_rate;
}
- (void)setProgressValus:(CGFloat)progressValus{
    if (progressValus<0.0 || progressValus >1.0) {
        return;
    }
    _progressValus = progressValus;
    
    [self sf_audioPause];
    [self.player seekToTime:CMTimeMake(floorf(self.sf_totalTime*progressValus), 1) toleranceBefore:CMTimeMake(1, 2) toleranceAfter:CMTimeMake(1, 2) completionHandler:^(BOOL finished) {
        if (finished) {
//            NSLog(@"seekComplete!!");
            [self sf_audioPlay];
        }
    }];
    
}

- (CGFloat)videoScale{
    if (!self.videoURL) {
        return 0;
    }
    //获取视频尺寸
    AVURLAsset *asset = [AVURLAsset assetWithURL:self.videoURL];
    NSArray *array = asset.tracks;
    CGSize videoSize = CGSizeZero;
    for (AVAssetTrack *track in array) {
        if ([track.mediaType isEqualToString:AVMediaTypeVideo]) {
            videoSize = track.naturalSize;
        }
    }
    return videoSize.height/videoSize.width;    
}

- (void)setVolumn:(CGFloat)volumn{
     if (volumn < 0 || volumn >1.0) {
//        return;
    }
    
//    self.player.volume = volumn;
    
//    NSArray *audioTracks = [self.playerItem.asset tracksWithMediaType:AVMediaTypeAudio];
//    NSMutableArray *allAudioParas = [NSMutableArray array];
//    for (AVAssetTrack *track in audioTracks) {
//        AVMutableAudioMixInputParameters *params = [AVMutableAudioMixInputParameters audioMixInputParameters];
//        [params setVolume:volumn atTime:kCMTimeZero];
//        [params setTrackID:track.trackID];
//        [allAudioParas addObject:params];
//    }
//    AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];
//    [audioMix setInputParameters:allAudioParas];
//    [self.player.currentItem setAudioMix:audioMix];
    
    NSURL *url = self.videoURL?self.videoURL:self.audioURL;
    AVAsset *asset = [AVAsset assetWithURL: url];
    NSArray *audioTracks = [asset tracksWithMediaType:AVMediaTypeAudio];
    
    NSMutableArray *allAudioParams = [NSMutableArray array];
    for (AVAssetTrack *track in audioTracks) {
        AVMutableAudioMixInputParameters *audioInputParams = [AVMutableAudioMixInputParameters audioMixInputParameters];
        [audioInputParams setVolume:volumn atTime:kCMTimeZero];
        [audioInputParams setTrackID:[track trackID]];
        [allAudioParams addObject:audioInputParams];
    }
    
    AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];
    [audioMix setInputParameters:allAudioParams];
    
    [self.playerItem setAudioMix:audioMix];
    
    
    
    
//    self.volumnSlider.value = volumn;
    
}
//- (CGFloat)volumn{
//    return self.volumnSlider.value;
//}

//控制的是音量键
//- (UISlider *)volumnSlider{
//    if (!_volumnSlider) {
//        MPVolumeView *volumnView = [[MPVolumeView alloc]initWithFrame:CGRectMake(-1000, 0, 0, 0)];
//        [KeyWindow addSubview:volumnView];
//        for (UIView *view  in volumnView.subviews) {
//            if ([[view.class description] isEqualToString:@"MPVolumeSlider"]) {
//                _volumnSlider = (UISlider *)view;
//                break;
//            }
//        }
//    }
//    return _volumnSlider;
//}


@end
